package model

import (
	j_log "config-client-v1/init/j-log"
	"gorm.io/gorm"
)

// Project 项目/工程
type Project struct {
	ID   int    `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
	UID  int    `gorm:"column:uid" json:"uid"`
	Name string `gorm:"column:name;comment:工程项目名称" json:"name"` // 工程项目名称
	Desc string `gorm:"column:desc;comment:工程项目描述" json:"desc"` // 工程项目描述

	ServerName string `json:"server_name" binding:"max=30"`
	ServerIP   string `json:"server_ip" gorm:"column:server_ip" binding:"max=15"`
	ServerPort int    `json:"server_port" gorm:"column:server_port" binding:"gte=0,lte=65535"`
	TimeSS     uint8  `json:"time_ss" gorm:"column:time_ss"`

	RedundantEnable uint8  `json:"redundant_enable" gorm:"column:redundant_enable" binding:"gte=0,lte=1"` // 是否开启冗余模块
	RedundantName   string `json:"redundant_name" gorm:"column:redundant_name" binding:"max=30"`          // 冗余IP地址
	RedundantIP     string `json:"redundant_ip" gorm:"column:redundant_ip" binding:"max=15"`              // 冗余IP地址
	RedundantPort   int    `json:"redundant_port" gorm:"column:redundant_port" binding:"gte=0,lte=65535"` // 冗余端口
	RedundantTimeSS uint8  `json:"redundant_time_ss" gorm:"column:redundant_time_ss"`

	CreateTime      *string    `gorm:"column:create_time;comment:添加时间" json:"create_time"`  // 添加时间
	UpdateTime      *string    `gorm:"column:update_time;comment:修改时间" json:"update_time"`  // 修改时间
	AdminID         int        ` gorm:"column:admin_id" json:"admin_id"`                    // 管理员id
	Del             uint8      `gorm:"column:del;comment:0.1." json:"del"`                  // 0.1.
	PPEList         []*PPE     `json:"ppe_list"  gorm:"foreignKey:ProjectID;references:ID"` // foreignKey 外表外键 references 当前表关联键
	FSEList         []*FSEquip `json:"fse_list"  gorm:"foreignKey:ProjectID;references:ID"` // foreignKey 外表外键 references 当前表关联键
	UserInfo        *UserSlim  `json:"user_info"  gorm:"foreignKey:ProjectID;references:ID"`
	UserList        []*User    `json:"user_list"  gorm:"foreignKey:ProjectID;references:ID"`
	SyncVariables   bool       `json:"-" gorm:"-"`                 // 是否同步变量到内存中, 在启动当前工程下的任意协议设备时同步
	ApiURL          string     `json:"api_url" gorm:"-"`           // 服务端接口地址
	WsURL           string     `json:"ws_url" gorm:"-"`            // 服务端接口地址
	RunningFSENum   int        `json:"running_fse_num" gorm:"-"`   // 运行中的自研设备总数
	RunningPPENum   int        `json:"running_ppe_num" gorm:"-"`   // 运行中的设备总数
	RunningTotalNum int        `json:"running_total_num" gorm:"-"` // 运行中的设备总数
	StartedNum      int        `json:"started_num" gorm:"-"`       // 已运行的设备总数
	RestartingNum   int        `json:"restarting_num" gorm:"-"`    // 启动中的设备总数 (包含正在启动和正在尝试重启的)
	StoppedNum      int        `json:"stopped_num" gorm:"-"`       // 未运行的设备总数 (包含未运行和已停止的)
}
type ProjectExt struct {
	Project
	PageGroupList []*PageGroup `json:"page_group_list" gorm:"-"`
	AlertTypeList []*AlertType `json:"alert_type_list" gorm:"-"`
	AuthRoleList  []*AuthRole  `json:"auth_role_list" gorm:"-"`
	FrameItemList []*FrameItem `json:"frame_item_list"  gorm:"-"` // 工程导出时 OPC UA|DA 客户端时专用
	DestDIR       string       `json:"dest_dir" gorm:"-"`
	ProjectExist  *Project     `json:"project_exist" gorm:"-"`
	AllowActions  []string     `json:"allow_actions" gorm:"-"`
	Importing     bool         `json:"importing" gorm:"-"`
}

// TableName Project's table name
func (m *Project) TableName() string {
	return "project"
}
func (m *ProjectExt) TableName() string {
	return "project"
}
func (m *Project) Exists(id int) (exist bool, err error) {
	err = DB.Where("id = ?", id).Limit(1).Find(m).Error
	if err != nil {
		return
	}
	if m.ID == 0 {
		return
	}
	exist = true
	return
}

func (m *Project) UpdateVariablesMap() (err error) {
	if m.SyncVariables == true {
		j_log.LogInfo([]interface{}{"SyncVariables 已完成"})
		return
	}
	j_log.LogInfo([]interface{}{"SyncVariables 正在同步工程变量到内存中..."})
	list := make([]*FrameItem, 0)
	err = DB.Where("project_id = ?", m.ID).Find(&list).Error
	if err != nil {
		return
	}
	for _, row := range list {
		v, ok := VariablesMap.Get(row.Addr)
		if ok {
			v.FrameItem = *row
		} else {
			variable := &Variable{
				FrameItem: *row,
				//WSClientMap: NewWSClientMap(),
			}
			VariablesMap.Set(row.Addr, variable)
		}
	}
	m.SyncVariables = true
	return
}

func ResetRunningProject() {
	RunningFSMap.RLock()
	runningFSENum := len(RunningFSMap.M)
	RunningFSMap.RUnlock()

	RunningPPEMap.RLock()
	runningPPENum := len(RunningPPEMap.M)
	RunningPPEMap.RUnlock()

	runningTotalNum := runningFSENum + runningPPENum

	if runningTotalNum == 0 {
		RunningProject.ID = 0
	}
}

func ProjectStartHook(projectID int) (err error) {
	if RunningProject.ID != 0 {
		return
	}
	RunningProject.ID = projectID
	// 更新工程全部变量到内存中
	//project := Project{}
	//err = DB.Preload("PPEList", func(tx *gorm.DB) *gorm.DB {
	//	return tx.Preload("FrameList", func(tx2 *gorm.DB) *gorm.DB {
	//		return tx2.Preload("FrameItem")
	//	})
	//}).Preload("FSEList", func(tx *gorm.DB) *gorm.DB {
	//	return tx.Preload("FSModule", func(tx2 *gorm.DB) *gorm.DB {
	//		return tx2.Preload("FrameItem")
	//	})
	//}).Where("id = ? AND del = 0", projectID).Limit(1).Find(&project).Error
	//if err != nil {
	//	return
	//}
	//if project.ID == 0 {
	//	return errors.New("无效的工程ID")
	//}
	//for _, ppe := range project.PPEList {
	//	err = ppe.UpdateVariablesMap()
	//	if err != nil {
	//		j_log.LogError([]interface{}{"ppe更新变量map失败", ppe.Name})
	//	}
	//}
	//for _, fse := range project.FSEList {
	//	fse.CalculateDataScale()
	//	err = fse.UpdateVariablesMap()
	//	if err != nil {
	//		j_log.LogError([]interface{}{"fse更新变量map失败", fse.Name})
	//	}
	//}

	/*--- 替代上面写法 ---*/
	variableList := make([]*FrameItem, 0)
	_ = DB.Where("project_id = ?", projectID).Find(&variableList).Error
	for _, row := range variableList {
		v, ok := VariablesMap.Get(row.Addr)
		if ok {
			v.FrameItem = *row
		} else {
			variable := &Variable{
				FrameItem: *row,
			}
			VariablesMap.Set(row.Addr, variable)
		}
	}
	LoadRunningExpPage(projectID)
	// 更新工程下的报警信息到内存中
	AlertTypeMap.Lock()
	defer AlertTypeMap.Unlock()
	list := make([]*AlertType, 0)
	err = DB.Where("project_id = ?", projectID).Find(&list).Error
	if err != nil {
		return
	}
	for _, v := range list {
		AlertTypeMap.M[v.Const] = v
	}
	return
}

func DeleteProject(projectID int) (err error) {
	err = DB.Transaction(func(tx *gorm.DB) (err error) {
		err = tx.Where("id = ?", projectID).Delete(&Project{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&User{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&FSEquip{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&FSModule{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&PPE{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&Frame{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&FrameItem{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&Page{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&PageGroup{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&UploadHistory{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&CommandHistory{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&UserToken{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&VarRecord{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&Variable{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&AlertType{}).Error
		if err != nil {
			return
		}
		err = tx.Where("project_id = ?", projectID).Delete(&AuthRole{}).Error
		if err != nil {
			return
		}
		return nil
	})
	// todo todo 删除工程下的所有相关文件
	return err
}
